﻿using AntdUI;
using CKS.Core.Framework;
using ImportPlcPointPosition.Core;
using ImportPlcPointPosition.Models.Table;
using ImportPlcPointPosition.Models.ViewModels;
using ImportPlcPointPosition.Utils;
using Mapster;
using Microsoft.IdentityModel.Tokens;
using MiniExcelLibs;
using NetTaste;
using S7.Net.Types;
using SqlSugar;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using ZR.Model.Models.ProductionControl;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static Vanara.PInvoke.User32;

namespace ImportPlcPointPosition.Controls
{
    public partial class DataPositionTableControl : BaseUserControl
    {

       

        public DataPositionTableControl()
        {
            InitializeComponent();
            InitPointTable();
            this.Load += BlockDbTable_Load;
            input1.Text = @"数据类型：\int\string[20]\real\lreal\   占位eg:\Array[1..100] of Byte";
        }
        /// <summary>
        /// 当前DB块
        /// </summary>
        public PlcBlockDb BlockDb;
        /// <summary>
        /// 当前PLC信息
        /// </summary>
        public PlcConfig CurrentPlc = null;

        public bool IsWatch = false;
        private bool AllowEditAfterUpdate = false;

        public BindingList<ImportData> PointDatas = new BindingList<ImportData>();

        SqlSugarClient db = null;
        //public BlockDbTable(PlcBlockDb blockDb, PlcConfig currentPlc)
        //{
        //    BlockDb = blockDb;
        //    CurrentPlc = currentPlc;
        //    InitializeComponent();
        //    InitPointTable();
        //    this.Load += BlockDbTable_Load;
        //}

        private void BlockDbTable_Load(object sender, EventArgs e)
        {
            if (DesignMode)
                return;
            db = SqlSugarHelper.MesDB;
            string desc = BlockDb.WriteFrom switch
            {
                1 => "写入方：PC",
                2 => "写入方：PLC",
                3 => "写入方：混合",
                _ => ""
            };
            lblDBText.Text = $"{desc} DB:{BlockDb.BlockDb}  模块:{BlockDb.ModuleCellText}";
            LoadPointData(CurrentPlc);
        }

        private void InitPointTable()
        {
            tbPoint.EditMode = TEditMode.None;
            tbPoint.Columns = new ColumnCollection();
            //tbPoint.TreeButtonSize = 12;
           // tbPoint.GapTree = 5;
            //tbPoint.DefaultExpand = true;
            tbPoint.Columns.Add(new Column("Id", "Id") { Fixed = true, KeyTree = "Children", Width = "100" }  );
            tbPoint.Columns.Add(new Column("ParentId", "ParentId") { Fixed = true, } );
           
           // tbPoint.Columns.Add(new Column("OrderNo", "") { Fixed = true ,KeyTree = "SubItems" ,Align = ColumnAlign.Center,Width="100"  } );     
            tbPoint.Columns.Add(new Column("Description", "名称", ColumnAlign.Left) {
                Fixed = true, KeyTree = "SubItems", Width = "120", Style = new Table.CellStyleInfo() { BackColor = Color.FloralWhite, ForeColor = Color.Black },
                //Render =renderName
            });
            tbPoint.Columns.Add(new Column("DataType", "数据类型") { Fixed = true, Style = new Table.CellStyleInfo() { BackColor = Color.FloralWhite, ForeColor = Color.Black } });
            tbPoint.Columns.Add(new Column("BytePositionStr", "偏移量") { Fixed = true, Style = new Table.CellStyleInfo() { BackColor = Color.PapayaWhip, ForeColor = Color.Gray } });
            tbPoint.Columns.Add(new Column("WatchValue", "监视值") { Fixed = true, Style = new Table.CellStyleInfo() { BackColor = Color.Yellow, ForeColor = Color.Black } });

            // tbPoint.Columns.Add(new Column("InitValue", "默认值") { Style = new Table.CellStyleInfo() { BackColor = Color.Yellow, ForeColor = Color.Black } });


            tbPoint.Columns.Add(new Column("EffectTypeCellText", "作用"));

            tbPoint.Columns.Add(new Column("ActionId", "动作编号"));
            tbPoint.Columns.Add(new Column("ActionKey", "动作Key"));

            tbPoint.Columns.Add(new Column("LinkActionId", "关联动作"));
            tbPoint.Columns.Add(new Column("DataId", "数据编号"));
            tbPoint.Columns.Add(new Column("LocationId", "位置/组"));
            tbPoint.Columns.Add(new Column("Remark", "备注") { Width = "100" });


            tbPoint.Columns.Add(new Column("WriteValue", "写入值"));
            tbPoint.Columns.Add(new ColumnSwitch("AutoWrite", "自动写", ColumnAlign.Center)
            {
                //支持点击回调
                Call = (value, record, i_row, i_col) => {
                    //执行耗时操作
                    Thread.Sleep(200);

                    var data =record as ImportData;
                    if (data.ParseType.ToLower().Contains("array"))
                    {
                        return false;
                    }
                    if (value)
                    {
                       
                        //if (!data.WriteValue.Contains(","))
                        if(data.WriteValue.IsNullOrEmpty())
                        {
                            MessageError("内容为空");
                            return false;
                        }    
                    }
                    
                    // AntdUI.Message.info(this.FindForm(), value.ToString(), autoClose: 1);
                    return value;
                }
            });
            tbPoint.Columns.Add(new Column("Operate", "操作") { Fixed = true });

            tbPoint.Bordered = true;
            tbPoint.EnableHeaderResizing = true;
            tbPoint.EmptyHeader = true;
            tbPoint.Gap = 6;
            tbPoint.VisibleHeader = true;
            tbPoint.CellClick += TbPoint_CellClick;
            tbPoint.CellBeginEditInputStyle += (s,e)=> {  
                e.Input.SelectAll();
                var col = tbPoint.Columns[e.ColumnIndex];
                AllowEditAfterUpdate = col.Key == "DataType";
            };
           
            
            tbPoint.CellEditComplete += TbPoint_CellEditComplete;
            tbPoint.CellButtonClick += TbPoint_CellButtonClick;
            tbPoint.CellPaint += TbPoint_CellPaint;
            ChangePointTableColumnVisible();
        }

        #region 监视数据变化效果
        // 存储渐变状态：单元格唯一标识 → (当前步数, 总步数)
        private Dictionary<Tuple<object, string>, (int CurrentStep, int TotalSteps)> _fadingCells = new();
        // 标记是否正在执行渐变循环
        private bool _isFadingLoopRunning = false;
        // 渐变参数（可调整）
        private const int _totalFadeSteps = 7; // 总渐变步数
        private const int _fadeIntervalMs = 50; // 每步间隔时间（ms）
                                                // 文本左对齐格式（全局复用，避免重复创建）
        private StringFormat _leftAlignFormat = new StringFormat { Alignment = StringAlignment.Near };

        private void TbPoint_CellPaint(object sender, TablePaintEventArgs e)
        {
            if (e.Column.Key == "WatchValue")
            {
                var record = e.Record as ImportData;
                if (record == null) return;

                var cellKey = new Tuple<object, string>(record.Guid, e.Column.Key);
                Color backgroundColor = Color.Yellow; // 默认黄色
                bool needdraw = true;
                // 检查是否处于渐变状态
                if (_fadingCells.TryGetValue(cellKey, out var fadeState)
                    && fadeState.CurrentStep < fadeState.TotalSteps)
                {
                    // 计算当前颜色（从红色→黄色渐变）
                    int greenValue = (int)(255 * (float)fadeState.CurrentStep / fadeState.TotalSteps);
                    backgroundColor = Color.FromArgb(255, greenValue, 0);
                }
                else if (_fadingCells.ContainsKey(cellKey))
                {
                    // 渐变结束，移除记录
                    _fadingCells.Remove(cellKey);
                }
                else
                {
                    needdraw = false;
                }
                if (needdraw)
                {
                    // 绘制背景和文本
                    using (var brush = new SolidBrush(backgroundColor))
                    {
                        e.g.Fill(brush, new Rectangle(e.Rect.X + 2, e.Rect.Y + 1, e.Rect.Width - 4, e.Rect.Height - 4));
                    }
                    var txtrect = new Rectangle(e.RectReal.X - 4, e.RectReal.Y + 6, e.RectReal.Width - 2, e.RectReal.Height - 2);

                    e.g.DrawText(record.WatchValue, tbPoint.Font, Brushes.Black, txtrect, _leftAlignFormat);
                }

            }
        }



        // 触发渐变效果（数据变化时调用）
        public void StartCellFade(ImportData record)
        {
            if (record == null) return;

            var cellKey = new Tuple<object, string>(record.Guid, "WatchValue");
            // 重置渐变状态（开始新的渐变）
            _fadingCells[cellKey] = (CurrentStep: 0, TotalSteps: _totalFadeSteps);

            // 启动渐变循环（如果尚未启动）
            if (!_isFadingLoopRunning)
            {
                _ = FadeAsyncLoop();
            }

            tbPoint.Invalidate();
        }

        // 异步渐变循环
        private async Task FadeAsyncLoop()
        {
            _isFadingLoopRunning = true;

            try
            {
                // 循环直到没有需要渐变的单元格
                while (_fadingCells.Count > 0)
                {
                    // 等待间隔时间（控制渐变速度）
                    await Task.Delay(_fadeIntervalMs);

                    // 更新渐变进度（假设在UI线程执行）
                    var keys = _fadingCells.Keys.ToList();
                    foreach (var key in keys)
                    {
                        if (_fadingCells.TryGetValue(key, out var state))
                        {
                            int newStep = Math.Min(state.CurrentStep + 1, state.TotalSteps);
                            _fadingCells[key] = (newStep, state.TotalSteps);
                        }
                    }

                    // 刷新表格显示最新颜色
                    tbPoint.Invalidate();
                }
            }
            finally
            {
                _isFadingLoopRunning = false;
            }
        }
        #endregion

        private object renderName(object arg1, object arg2, int arg3)
        {
            return $"   {arg1}";
        }

        List<string> listenColumns = new List<string>() { "WatchValue", "WriteValue", "Operate", "AutoWrite" };

        List<string> runHideColumn = new List<string>() { "ParentId", "Id" };
        public void ChangePointTableColumnVisible()
        {
            if (DesignMode)
                return;
            //监视状态显示 监视值 、写入值 两列
            foreach (var column in tbPoint.Columns)
            {
                if (listenColumns.Contains(column.Key))
                {
                    if (App.PlcClient != null && App.PlcClient.plcSession.IsConnected)
                        column.Visible = true;
                    else
                        column.Visible = false;
                }
                if(runHideColumn.Contains(column.Key))
                {
                    if (App.PlcClient != null && App.PlcClient.plcSession.IsConnected)
                        column.Visible = false;
                    else
                        column.Visible = true;
                }

            }
            if(this.IsHandleCreated)
                this.Invoke(() => { panel1.Enabled = !IsWatch; });

        }

        private void TbPoint_CellButtonClick(object sender, TableButtonEventArgs e)
        {
            if (App.PlcClient == null)
                return;
            var one = e.Record as ImportData;
            var writeModel = one.Adapt<CksPlcDataPosition>();
            try
            {
                switch (e.Btn.Id)
                {
                    case "read":
                        //one.Value = GlobalIoc.PlcClient.GetStringValue(one);
                        break;
                    case "write"://写入
                        App.PlcClient.SetValue(writeModel, one.WriteValue);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageError(ex.Message);
            }
        }
        private void TbPoint_CellEditComplete(object sender, EventArgs e)
        {
            if(AllowEditAfterUpdate)
                ReBindPointDatas(out List<ImportData> datas);
        }
        private void TbPoint_CellClick(object sender, TableClickEventArgs e)
        {

            if (e.Button == MouseButtons.Left)
            {
                var columns =tbPoint.Columns.ToList().FindAll(a => a.Visible);
                var col = columns[e.ColumnIndex];
                if(IsWatch)
                {
                    switch (col.Key)
                    {
                        //左键编辑
                        case "Description":
                        case "AutoWrite":
                        case "WriteValue":
                        case "ActionId":
                        case "DataId":
                        case "LinkActionId":
                        case "Remark":
                        case "LocationId":
                    
                            tbPoint.EnterEditMode(e.RowIndex, e.ColumnIndex);
                            break;
                    }
                }
                else
                {
                    switch (col.Key)
                    {
                        case "WriteFromCellText":
                        case "EffectTypeCellText":
                        case "BytePosition":
                        case "OrderNo":
                        case "Id":
                        case "WatchValue":
                        case "BytePositionStr":
                            break;
                        default:

                            tbPoint.EnterEditMode(e.RowIndex, e.ColumnIndex);
                            break;
                    }
                }
                
            }
            else if (e.Button == MouseButtons.Right)
            {
                var data = e.Record as ImportData;
                var index = PointDatas.IndexOf(data);
                var indexId = index + 1;



                if (index == -1 && data.ParentId ==0)
                    return;


                if (PointDatas.Count == 0 || IsWatch)
                {
                    List<IContextMenuStripItem> testmenus = new List<IContextMenuStripItem>();
                    testmenus.Add(new ContextMenuStripItem("test") { ID = "test" });
                  //  AntdUI.ContextMenuStrip.open(tbPoint, OnClickRightMenu(data), testmenus.ToArray());
                    return;
                }
                
               
                


                List<IContextMenuStripItem> menus = new List<IContextMenuStripItem>();
                menus.Add(new ContextMenuStripItem("上方插入1行") { ID = "add" });
                menus.Add(new ContextMenuStripItem("删除")
                {
                    ID = "delete"
                    //IconSvg = "CloseOutlined"
                });
               
               
                AntdUI.ContextMenuStrip.open(tbPoint, OnClickRightMenu(data), menus.ToArray());
            }


        }

        private Action<ContextMenuStripItem> OnClickRightMenu(ImportData data)
        {
            var lst = PointDataToList(PointDatas);
            var index = lst .IndexOf(data);
            
            Action<ContextMenuStripItem> action = (menu) =>
            {
                switch (menu.ID)
                {
                    case "add":

                        AddRows(lst,data);
                        break;
                    case "delete":
                        if(data.ParentId>0)
                        {
                            var sub =lst.Find(a => a.Id == data.ParentId);
                            var subs =sub.SubItems.ToList();
                            subs.Remove(data);
                            sub.SubItems = subs.ToArray();

                        }
                        PointDatas.Remove(data);
                        DeleteCheckNodes(data);
                        btnSaveAll_Click(null, null);
                        break;
                    
                    case "test":

                        //测试读取
                        TestReade();
                        break;
                    default:
                        break;
                }
                ReBindPointDatas(out List<ImportData> datas);

            };
            return action;
        }

        


        private void DeleteCheckNodes(ImportData data)
        {

            db.Deleteable<CksPlcDataPosition>().Where(a => a.Id == data.Id).ExecuteCommand();
            if(data.SubItems!=null&&data.SubItems.Length>0)
            {
                foreach (var item in data.SubItems)
                {
                    DeleteCheckNodes(item);
                }
            }
        }

        private void TestReade()
        {
            try
            {
              
                string cmd = "DB3000.DBD2";
                var mds =cmd.Split('.');
                int db =int.Parse(mds[0].Replace("DB", ""));
                int startPos = int.Parse(Regex.Match(mds[1], "[0-9]+").Value);

                var dd =App.PlcClient.plcSession.Read(S7.Net.DataType.DataBlock,db,startPos,S7.Net.VarType.Real,1);
            
            }
            catch (Exception)
            {

            }
        }

        

        private void LoadPointData(PlcConfig config)
        {
            if (config == null)
                return;
            PointDatas.Clear();
            var plcId = config.Id;

            var plcdb = BlockDb;
            var ds = db.Queryable<CksPlcDataPosition>()
                .Where(a => a.PlcId == plcId && a.BlockDb == plcdb.BlockDb)
                .OrderBy(a => new {  a.OrderNo }).ToList().Adapt<List<ImportData>>();

            int rowid = 0;
            foreach (var item in ds)
            {
                item.BytePosition = item.BytePosition;
                rowid++;
                item.OrderNo = rowid;
                ConvertToS7Type(item);

            }
          

            var results = new List<ImportData>();
            //加载父子关系
            BuildTreeData(ds, results);
           
            PointDatas = new BindingList<ImportData>(results);

            ReBindPointDatas(out List<ImportData> datas);//查询数据

            results = new List<ImportData>();
            BuildTreeData(datas, results);

            PointDatas = new BindingList<ImportData>(results);



            tbPoint.Binding(PointDatas);

            foreach (var item in PointDatas)
            {
                if(item.ParseType.ToLower()=="struct")
                    tbPoint.Expand(item);
            }
        }

        /// <summary>
        /// 构造树形结构
        /// </summary>
        /// <param name="AllDatas"></param>
        private  void BuildTreeData(List<ImportData> AllDatas, List<ImportData> results, ImportData parent =null)
        {



            int rootId = parent == null ?0:parent.Id;
            List<ImportData> childrens = new List<ImportData>();
            
            childrens = AllDatas.FindAll(a => a.ParentId == rootId);
            if (childrens.Count == 0)
                return;
            /*
             遍历根节点
                
             */

            if(parent == null)
            {
                results.AddRange(childrens);

                foreach (var child in childrens)
                {
                    //查找子节点，存在子节点则添加
                    BuildTreeData(AllDatas, results, child);
                }
            }
            else
            {
                var childs = AllDatas.FindAll(a => a.ParentId == parent.Id);
                parent.SubItems = childs.ToArray();
                foreach (var child in parent.SubItems)
                {
                    BuildTreeData(AllDatas, results, child);
                }
            }

           

        }


        private void btnAdd_Click(object sender, EventArgs e)
        {
            var lst = PointDataToList(PointDatas);
            AddRows(lst);
        }

        private void AddRows(List<ImportData> all,ImportData checkData=null)
        {
            var plcdb = BlockDb;
            var pId = checkData == null ? 0 : checkData.ParentId;
            var row = new ImportData()
            {
                WriteFrom = plcdb.WriteFrom
                ,
                WorkStationCode = CurrentPlc.WorkstationCode,
                PlcId = CurrentPlc.Id,
                BlockDb = plcdb.BlockDb,
                ParentId = pId,
                DataType = "Struct", //默认给个Int
            };

            if (plcdb.WriteFrom <= 2)
                row.WriteFrom = plcdb.WriteFrom;
            else
                row.WriteFrom = 2;


            if (checkData!=null)
            {
                if(checkData.ParentId == 0)
                {
                    //根目录插入
                    // PointDatas.Insert(index, row);
                    var index = PointDatas.IndexOf(checkData);
                    PointDatas.Insert(index, row);
                }
                else
                {
                    //子目录插入
                   var parent = all.Find(a => a.Id == checkData.ParentId);
                    var subs =parent.SubItems.ToList();
                    var index =subs.IndexOf(checkData);
                    subs.Insert(index,row);
                    parent.SubItems = subs.ToArray();
                }
               
            }
            else
                PointDatas.Add(row);
        }

        Dictionary<int,int> structdic = new Dictionary<int,int>();
        private void btnSaveAll_Click(object sender, EventArgs e)
        {
            if (PointDatas.Count <= 0)
                return;


            Stopwatch stopwatch = Stopwatch.StartNew();


            bool flag = ReBindPointDatas(out List<ImportData> datas);
           
           
            if (!flag) return;
            //遍历数据保存到数据块
            //自动为Struct分配LastID
            var lastParentID = 0;
            Dictionary<int,int> dicRealId = new Dictionary<int,int>();
            foreach (var point in datas)
            {
                //

                var model = point.Adapt<CksPlcDataPosition>();

                model.BlockDbId = BlockDb.Id;
                model.Module = BlockDb.Module;
                if (point.Id == 3611)
                {

                }

                if (model.Id == 0)
                {
                   
                    if (model.ParseType.ToLower().Equals("struct"))
                    {
                        if (dicRealId.ContainsKey(model.TempParentId))
                            model.ParentId = dicRealId[model.TempParentId];
                        lastParentID = db.Insertable(model).ExecuteReturnIdentity();
                        // id,realid
                        //structdic.Add(model.StructId, lastParentID);
                        if(!dicRealId.ContainsKey(model.TempId))
                            dicRealId.Add(model.TempId, lastParentID);
                    }
                    else
                    {
                        if (dicRealId.ContainsKey(model.TempParentId))
                            model.ParentId = dicRealId[model.TempParentId];
                        db.Insertable(model).ExecuteReturnIdentity();
                    }
                   
                }
                else
                {
                    db.Updateable(model).ExecuteCommand();
                }

            }

            var plcdb = BlockDb;
            plcdb.BlockLength = PointDatas[0].BlockLength;

            db.Updateable(plcdb).ExecuteCommand();


            LoadPointData(CurrentPlc);

            MessageBoxShow("保存成功");
        }

        public void BindSource(BindingList<ImportData> lst)
        {
            PointDatas = lst;
            tbPoint.Binding(PointDatas);
        }

        #region 计算偏移2.0
        /// <summary>
        /// 计算偏移量
        /// </summary>
        /// <param name="lst"></param>
        private void CalcOffsetSize(List<ImportData> lst)
        {
            decimal numBytes = 0.0m;
            int orderno = 0;
            foreach (var item in lst)
            {
                orderno++;
                item.OrderNo = orderno;
                if (string.IsNullOrEmpty(item.DataType))
                    throw new Exception("数据类型不能为空");
                GetVariableOffset(item);
                //判断是否数组
                if (IsArrayType(item.ParseType, out int arrayLenth, out string ParseType))
                {
                    IncrementToEven(ref numBytes);
                    //对齐后 赋值起始位置
                    item.BytePosition = numBytes;
                    for (int i = 0; i < arrayLenth; i++)
                    {
                        //计算偏移量
                        var result = GetIncreasedNumberOfBytes(ParseType, numBytes);
                        numBytes = result.numBytes;
                    }

                }
                else
                {
                    //检查是否需要对齐
                    var result = GetIncreasedNumberOfBytes(item.DataType.ToLower(), numBytes);
                    item.BytePosition = result.byteposition; //对齐后的位置

                    numBytes = result.numBytes;
                }
                //数组的长度后赋值  2.1 - 0   = 2.1 但是3字节
                item.ByteLength = Math.Ceiling((numBytes - item.BytePosition)).ObjToInt();


            }
        }


        public (decimal numBytes, decimal byteposition, decimal length) GetIncreasedNumberOfBytes(string ParseType, decimal numBytes)
        {
            (decimal numBytes, decimal byteposition, decimal length) result = (0, 0, 0);

            var bytesize = ParseType switch
            {
                "struct" => 0,
                "byte" => 1,
                "int" => 2,
                "int16" => 2,
                "word" => 2,
                "dword" => 4, //uint
                "dint" => 4,
                "int32" => 4,
                "real" => 4,
                "float" => 4,
                "lreal" => 8,
                "dtl" => 12,
                "dt" => 8,
                "bool" => 0.1m,
                _ => 1
            };

            if (bytesize == 1 && ParseType.Contains("string"))
            {
                bytesize = Regex.Match(ParseType, "[0-9]+").Value.ObjToInt() + 2;
            }
            //如果是1字节，代表需要向上取整
            if (bytesize == 1)
            {
                numBytes = Math.Ceiling(numBytes);
            }


            if (bytesize > 1 || bytesize == 0) //struct 和大于1 都需要进行对齐
            {
                IncrementToEven(ref numBytes);
            }
            result.numBytes = numBytes + bytesize;
            result.byteposition = numBytes;
            result.length = bytesize;
            //小数部分如果大于8 进1
            string f1 = result.numBytes.ToString("f1");
            int end = f1.Substring(f1.IndexOf('.') + 1).ObjToInt();
            if (end >= 8) //小数满8进1
            {
                //向上取整
                result.numBytes = Math.Ceiling(result.numBytes);
            }
            return result;
        }


        /// <summary>
        /// 将偏移量进行偶数对其
        /// </summary>
        /// <param name="numBytes"></param>
        private static void IncrementToEven(ref decimal numBytes)
        {
            numBytes = Math.Ceiling(numBytes);
            if (numBytes % 2 > 0) numBytes++;
        }

        #endregion
        /// <summary>
        /// 重新绑定点位数据，需要重新计算偏移值
        /// </summary>
        private bool ReBindPointDatas(out List<ImportData> lst)
        {
            lst = new List<ImportData>();
            var tempPointDatas = PointDatas;
            try
            {
                Stopwatch stopwatch = Stopwatch.StartNew();
               
                BindSource(new BindingList<ImportData>()); //做这个操作是为了先和UI解绑 不然不存数据会卡
                //移除parentid不为0的 平铺到List，计算偏移，计算偏移时插入struct
                lst = PointDataToList(tempPointDatas);
                Debug.WriteLine($" PointDataToList 耗时 {stopwatch.ElapsedMilliseconds}ms ");
                stopwatch.Restart();

                var plcdb = BlockDb;
                CalcOffsetSize(lst);
                for (int i = 0; i < lst.Count; i++)
                {
                    var item = lst[i];
                    item.OrderNo = i + 1;
                    item.BlockDb = plcdb.BlockDb;
                    item.WorkStationCode = CurrentPlc.WorkstationCode;
                    item.PlcId = CurrentPlc.Id;
                }

                //遍历完成，如果最后是bool结尾进行+1操作
                var last = lst.LastOrDefault();
                if (last == null)
                    return false;
                if (string.IsNullOrEmpty(last.DataType))
                    throw new Exception("数据类型不能为空");
                int fixEnd = 0;
                if (last.DataType.ToLower().Equals("bool"))
                    fixEnd = 1;

                int blockLenth = (int)last.BytePosition + last.ByteLength + fixEnd;
                if (blockLenth % 2 != 0)
                    blockLenth++;
                foreach (var item in lst)
                {
                    item.BlockLength = blockLenth;

                    //如果是数组追加子元素
                    if (IsArrayType(item.ParseType, out int arrayLenth, out string ParseType))
                    {
                        var SubItems = new List<ImportData>();
                        var size = GetTypeOffset(ParseType);
                        var byteOffset = item.BytePosition; 
                        for (int i = 0; i < arrayLenth; i++)
                        {
                           
                            if(i!=0)
                                byteOffset = size + byteOffset;
                            if (ParseType == "bool")
                            {
                                string f1 = byteOffset.ToString("f1");
                                int end = f1.Substring(f1.IndexOf('.') + 1).ObjToInt();
                                if (end >= 8) //小数满8进1
                                {
                                    byteOffset = ((int)byteOffset) + 1;
                                }
                            }
                            SubItems.Add(new ImportData
                            {
                                Description = $"[{i + 1}]", //数组编号
                                OrderNo = i + 1,
                                BlockDb = item.BlockDb,
                                ByteLength = (int)size,
                                DataType = ParseType,
                                ParseType = ParseType,
                                BytePosition = byteOffset
                            });
                        }
                        item.SubItems = SubItems.ToArray();
                        if(ParseType != "char")
                            item.Operate = null;

                    }
                }
                Debug.WriteLine($" 设置SubItems 耗时 {stopwatch.ElapsedMilliseconds}ms ");
                stopwatch.Stop();

                BlockDb.BlockLength = blockLenth;
                return true;
            }
            catch (Exception ex)
            {
                MessageError(ex.Message);
                return false;
            }
            finally
            {
                BindSource(tempPointDatas);
            }
        }

        public static List<ImportData> BuildDataView(List<ImportData> alls, List<ImportData> child,ref int orderNo)
        {
           
            //var children = alls.FindAll(a => a.ParentId == parentId).GroupBy(a => a.ParentId);
         

         
            foreach (var item in child)
            {
                alls.Add(item);
                item.OrderNo = ++orderNo;
                if(item.ParseType == "struct")
                {
                    //查找子元素

                }

                if(item.SubItems!=null  && !item.ParseType.IsS7Array() && item.SubItems.Count()>0)
                {
                    BuildDataView(alls, item.SubItems.ToList(),ref orderNo);
                  
                }
            }
            return alls.OrderBy(a=>a.OrderNo).ToList();
        }

        private void btnImportExcel_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "(博图db块文件)|*.db";
            var dialog = ofd.ShowDialog();
            if (dialog == DialogResult.OK)
            {

                try
                {
                    var plcdb = BlockDb;


                    //读取文件
                    string content = File.ReadAllText(ofd.FileName);
                    Regex regex = new Regex(@"(.+ : .+;[\s].+)|(.+ : .+;)|(.+ : Struct)|END_STRUCT;");
                    var matches = regex.Matches(content).ToList();

                    List<ImportData> ds = new List<ImportData>();
                    var parser = new S7CodeParser();
                    var eles = parser.Parse(content);
                    parser.ExpandCustomTypes(eles);
                    parser.FixIdsAndParentIds(eles);
                    var dataBlock  = eles.Find(a => a.Type == "DATA_BLOCK").Children.Find(a=>a.Type == "STRUCT");
                   
                    BuildImportData(eles,dataBlock.Children,ds);

                   //  S7ParserText(matches, ds);

                    //  var ds = MiniExcel.Query<ImportData>(ofd.FileName).ToList();

                    foreach (var item in ds)
                    {
                        item.BlockDbId = plcdb.Id;
                        if (plcdb.WriteFrom <= 2)
                            item.WriteFrom = plcdb.WriteFrom;
                        else
                            item.WriteFrom = 2;
                    }

                    PointDatas.Clear();
                    PointDatas.AddRange(ds);

                    db.Deleteable<CksPlcDataPosition>()
                     .Where(a => a.PlcId == CurrentPlc.Id && a.BlockDb == plcdb.BlockDb)
                     .ExecuteCommand();
                    btnSaveAll_Click(null, null);
                }
                catch (Exception ex)
                {
                    MessageBoxShow("解析异常，请检查文件格式");
                }

            }
        }

        private void BuildImportData(List<Element> eles, List<Element> Children, List<ImportData> ds)
        {
            foreach (var item in Children)
            {
               
                ImportData data = new ImportData();
                data.Description = item.Name;
                data.DataType = item.Type;
                data.Remark = item.Comment;
                data.TempParentId = item.ParentId;
                data.TempId =item.Id;

                ds.Add(data);
                var udt = eles.Find(a => a.Type == "TYPE" && a.Name == item.Type);//自定义类型
              
                if (udt != null)
                { //用户自定义类型：

                    data.DataType = "STRUCT";
                   
                }
          
                if(item.Children.Count>0)
                {
                    BuildImportData(eles,item.Children,ds);
                }
            }
        }

        private static void S7ParserText(List<Match> matches, List<ImportData> ds)
        {
            matches.RemoveAt(matches.Count - 1);//因为没有匹配最开头的Struct，所以去掉最后的那个

            int currentRootId = 0;
            int TempID = 0;
            Stack<int> roots = new Stack<int>();
            foreach (Match match in matches)
            {
                string[] arrs = match.Value.Split(':');
                ImportData data = new ImportData();
                try
                {
                    TempID++;
                    data.Description = arrs[0].Trim();
                    if (match.Value.EndsWith("Struct"))
                    {
                        //结构开始
                        currentRootId = TempID;
                        roots.Push(currentRootId);
                    }
                    if (data.Description.StartsWith("END_STRUCT"))
                    {

                        roots.TryPop(out int res);
                        if (roots.Count == 0)
                            currentRootId = 0;
                        else
                        {
                            currentRootId = roots.Pop();
                            roots.Push(currentRootId);
                        }
                        //结构结束
                        continue;
                    }

                    data.TempId = TempID;
                    data.TempParentId = currentRootId;
                    if (arrs[1].Trim().Equals("Struct"))
                    {
                        data.DataType = "Struct";
                    }
                    else
                    {
                        data.DataType = arrs[1].Substring(0, arrs[1].IndexOf(';')).Trim();
                    }

                    if (arrs[1].Contains("空模式"))
                    {
                    }
                    if (arrs[1].Contains("//")) //注释
                    {
                        data.Remark = arrs[1].Split("//")[1].Trim();
                    }

                    ds.Add(data);
                }
                catch (Exception ex)
                {

                    throw;
                }
            }
        }

        private void btnLoadData_Click(object sender, EventArgs e)
        {
            LoadPointData(CurrentPlc);
        }

        private void btnDeleteAll_Click(object sender, EventArgs e)
        {
            var result = MessageBoxWarn("删除警告", "确认要删除当前DB块的所有点位数据吗");
            if (result == DialogResult.OK)
            {
            
                var plcdb = BlockDb;
                db.Deleteable<CksPlcDataPosition>()
                    .Where(a => a.PlcId == CurrentPlc.Id && a.BlockDb == plcdb.BlockDb)
                    .ExecuteCommand();
                LoadPointData(CurrentPlc);
                MessageInfo("删除成功");
            }
        }
    }
}
